﻿Imports System.Collections.ObjectModel
Imports System.ComponentModel

Namespace ViewModel
    Public Class TreeNodeViewModel(Of T)
        Inherits AbstractViewModel
        Implements IEditableObject

#Region "Fields"

        Public Shared ReadOnly MockChild As New TreeNodeViewModel(Of T)()

        Private _bindingData As T

        Private _parent As TreeNodeViewModel(Of T)

        Private _children As ObservableCollection(Of TreeNodeViewModel(Of T))

        Private _isEditing As Boolean
        Private _nameEdit As String

        Private _isSelected As Boolean
        Private _isExpanded As Boolean
        Private _isCollapsed As Boolean

        Private _level As Integer

        Private _nodeType As String

#End Region

#Region "Constructors"

        Public Sub New(ByVal data As T, ByVal parent As TreeNodeViewModel(Of T), ByVal lazyLoadChildren As Boolean)
            Me._bindingData = data
            Me._parent = parent
            Me._children = New ObservableCollection(Of TreeNodeViewModel(Of T))

            If lazyLoadChildren Then
                Me.Children.Add(MockChild)
            End If
        End Sub

        ''' <summary>
        ''' This constructor is used to create dummy-child instance.
        ''' </summary>
        Protected Sub New()

        End Sub

#End Region

#Region "Delegate and Event"

        Public Event ChildNodeAdded As EventHandler(Of TreeNodeEventArgs(Of T))
        Public Event ChildNodeRenamed As EventHandler(Of TreeNodeEventArgs(Of T))
        Public Event ChildNodeRemoved As EventHandler(Of TreeNodeEventArgs(Of T))

        Protected Overridable Sub OnChildNodeAdd(ByVal e As TreeNodeEventArgs(Of T))
            Dim childNodeAddHandler As EventHandler(Of TreeNodeEventArgs(Of T)) = Me.ChildNodeAddedEvent
            If childNodeAddHandler IsNot Nothing Then
                childNodeAddHandler.Invoke(Me, e)
            End If
        End Sub

        Protected Overridable Sub OnChildNodeRenamed(ByVal e As TreeNodeEventArgs(Of T))
            Dim childNodeRenameHandler As EventHandler(Of TreeNodeEventArgs(Of T)) = Me.ChildNodeRenamedEvent
            If childNodeRenameHandler IsNot Nothing Then
                childNodeRenameHandler.Invoke(Me, e)
            End If
        End Sub

        Protected Overridable Sub OnChildNodeRemoved(ByVal e As TreeNodeEventArgs(Of T))
            Dim childNodeRemoveHandler As EventHandler(Of TreeNodeEventArgs(Of T)) = Me.ChildNodeRemovedEvent
            If childNodeRemoveHandler IsNot Nothing Then
                childNodeRemoveHandler.Invoke(Me, e)
            End If
        End Sub

#End Region

#Region "Properties"

        Public ReadOnly Property BindingData As T
            Get
                Return Me._bindingData
            End Get
        End Property

        ''' <summary>
        ''' Returns true if this object's Children have not yet been populated.
        ''' </summary>
        Public ReadOnly Property HasMockChild As Boolean
            Get
                Return Me.Children.Count = 1 AndAlso Me.Children(0) Is MockChild
            End Get
        End Property

        ''' <summary>
        ''' Gets the parent node.
        ''' </summary>
        Public ReadOnly Property Parent() As TreeNodeViewModel(Of T)
            Get
                Return _parent
            End Get
        End Property

        ''' <summary>
        ''' Gets the children nodes.
        ''' </summary>
        Public ReadOnly Property Children() As ObservableCollection(Of TreeNodeViewModel(Of T))
            Get
                Return _children
            End Get
        End Property

        Public Property IsEditing() As Boolean
            Get
                Return _isEditing
            End Get
            Private Set(ByVal value As Boolean)
                If _isEditing <> value Then
                    _isEditing = value
                    OnPropertyChanged("IsEditing")
                End If
            End Set
        End Property

        ''' <summary>
        ''' Gets/sets whether the node associated with this object is expanded.
        ''' </summary>
        Public Property IsExpanded() As Boolean
            Get
                Return Me._isExpanded
            End Get
            Set(ByVal value As Boolean)
                If value <> Me._isExpanded Then
                    Me._isExpanded = value
                    Me.OnPropertyChanged("IsExpanded")
                End If

                '' Expands all the way up to the root.
                If Me._isExpanded AndAlso Me._parent IsNot Nothing Then
                    Me._parent.IsExpanded = True
                End If

                '' Lazy loads the child items, if necessary.
                If Me.HasMockChild Then
                    Me.Children.Remove(MockChild)
                    Me.LoadChildren()
                End If
            End Set
        End Property

        ''' <summary>
        ''' Gets/sets whether the node associated with this object is selected.
        ''' </summary>
        Public Property IsSelected() As Boolean
            Get
                Return Me._isSelected
            End Get
            Set(ByVal value As Boolean)
                If value <> Me._isSelected Then
                    Me._isSelected = value
                    Me.OnPropertyChanged("IsSelected")
                End If
            End Set
        End Property

        Public ReadOnly Property Level() As Integer
            Get
                If Me.Parent Is Nothing Then
                    Me._level = 1
                Else
                    Me._level = Me.Parent.Level + 1
                End If

                Return Me._level
            End Get
        End Property

        Public Overridable Property NodeType() As String
            Get
                Return Me._nodeType
            End Get
            Set(ByVal value As String)
                Me._nodeType = value
                Me.OnPropertyChanged("NodeType")
            End Set
        End Property

#End Region

#Region "Commands"

#End Region

#Region "Methods"

        Protected Overridable Sub LoadChildren()

        End Sub

#End Region

#Region "Command Actions"

        Protected Overridable Sub ExecuteRename()

        End Sub

        Protected Overridable Sub ExecuteDelete()

        End Sub

        Protected Overridable Sub ExecuteAddNode()

        End Sub

#End Region

#Region "IEditableObject Members"

        Public Sub BeginEdit() Implements System.ComponentModel.IEditableObject.BeginEdit
            Me._nameEdit = Me.DisplayName
            Me.IsEditing = True
        End Sub

        Public Sub CancelEdit() Implements System.ComponentModel.IEditableObject.CancelEdit
            Me.DisplayName = Me._nameEdit
            Me.IsEditing = False
        End Sub

        Public Sub EndEdit() Implements System.ComponentModel.IEditableObject.EndEdit
            Me.IsEditing = False
        End Sub

#End Region
        
    End Class
End Namespace
